package CommentApi.Util;

import lombok.SneakyThrows;


import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;


public class EntityGenerator {
    private EntityGenerator(){}

    public static int generatorInt(){
        return 1;
    }
    //左闭右开
    public static int generatorInt(int min,int max){
        return new Random(System.currentTimeMillis()).nextInt(max) % (max - min + 1) + min;
    }


    public static String generatorString(int maxLength,boolean isChinese){
        final StringBuilder builder = new StringBuilder();
        final Random random = new Random();
        if (isChinese){
            for (int i = 0; i < maxLength; i++) {
                builder.append(generatorChineseWord(random));
            }
        }else {
            char[] ch = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
                    'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
                    'j', 'k','l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
            for (int i = 0; i < maxLength; i++) {
                builder.append(ch[random.nextInt(ch.length)]);
            }
        }
        return builder.toString();
    }
    public static char generatorChineseWord(Random random){
        // Unicode中汉字所占区域\u4e00-\u9fa5,将4e00和9fa5转为10进制
        int start = Integer.parseInt("4e00", 16);
        int end = Integer.parseInt("9fa5", 16);
        // 随机值
        int code = random.nextInt(end - start + 1) + start;
        return (char) code;
    }

    @SneakyThrows
    public static <T> T generatorEntity(Class<T> c){
        final T t;
        if (needReflect(c)){
            t = c.newInstance();
            setDefaultValue(c, t);
        }else {
            t = (T)generateBase(c);
        }
        return t;
    }

    /**
     * 默认跳过存在泛型的field
     * @param c 需要获取值的反射
     * @param o 被赋值的object
     * @throws Exception
     */
    private static void setDefaultValue(Class c, Object o) throws Exception {
        Field[] declaredFields = c.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            declaredField.setAccessible(true);
            Type genericType = declaredField.getGenericType();
            //是泛型才进入这个if
            if(!(genericType instanceof Class)){
                continue;
            }
           //todo next must fix,这里可能是泛型不知道怎么赋值
            Class type = (Class) genericType;
            if (needReflect(type)) {
                if (type.equals(Object.class)){
                    declaredField.set(o,new Object());
                }else if (type.isAssignableFrom(List.class)) {
                    handleList(declaredField,o);
                } else if (type.isAssignableFrom(Date.class)) {
                    declaredField.set(o, new Date());
                } else if (type.isArray()) {
                    handleArray(declaredField,o,type);
                } else {
                    //自定义javabean
                    Object o1 = type.newInstance();
                    //给对象的字段设置值
                    declaredField.set(o, o1);
                    setDefaultValue(type,o1);
                }
            }else {
                handleBase(declaredField, type, o);
            }
        }
    }
    private static Object generateBase(Class t){
        Object value;
        switch (t.getName()){
            case "java.lang.Double":
            case "double":
                value = Math.random() * 100;
                break;
            case "java.lang.Integer":
            case "int":
                value = generatorInt();
                break;
            case "java.lang.Float":
            case "float":
                value = ((float) Math.random());
                break;
            case "java.lang.Byte":
            case "byte":
                value = (byte) generatorInt();
                break;
            case "java.lang.Boolean":
            case "boolean":
                value = true;
                break;
            case "java.lang.Long":
            case "long":
                value = 10000000L;
                break;
            case "java.lang.Short":
            case "short":
                value = (short) 100;
                break;
            case "java.lang.Character":
            case "char":
                value = generatorChineseWord(new Random());
                break;
            case "java.lang.String":
                value = generatorString(10, false)+generatorString(10, true);
                break;
            case "java.util.Date":
                value = new Date();
                break;
            case "java.math.BigDecimal":
                value = new BigDecimal(1000.01);
                break;
            case "java.math.BigInteger":
                value = new BigInteger("80808080");
                break;
            default:
                throw new RuntimeException("不支持的数据类型");
        }
        return value;
    }
    private static void handleBase(Field declaredField,Class fieldType,Object source){

        try {
            declaredField.set(source,generateBase(fieldType));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**处理字段为集合的情况
     * @param declaredField 字段
     * @param o 字段所属对象
     * @throws Exception 反射新对象抛出异常
     */
    private static void handleList(Field declaredField,Object o) throws Exception{
        List<Object> dataList = new ArrayList<>();
        Type genericType = declaredField.getGenericType();
        if (genericType instanceof ParameterizedType) {
            ParameterizedType pt = (ParameterizedType) genericType;
            //得到泛型里的class类型对象
            Class<?> c2 = ( Class<?> ) pt.getActualTypeArguments()[0];
            if (needReflect(c2)) {
                Object generic = c2.newInstance();
                Object generic1 = c2.newInstance();
                dataList.add(generic);
                dataList.add(generic1);
                setDefaultValue(c2, generic);
                setDefaultValue(c2, generic1);
            }else {
                dataList.add(generateBase(c2));
                dataList.add(generateBase(c2));
            }
            declaredField.set(o, dataList);
        }
    }

    /**处理字段为数组的情况
     * @param declaredField 字段
     * @param o 字段所属对象
     * @param c 字段类型
     * @throws Exception 反射新对象抛出异常
     */
    private static void handleArray(Field declaredField,Object o,Class c) throws Exception{
        Class<?> componentType = c.getComponentType();
        Object[] oArray = getObjectArray(componentType);
        oArray[0] = componentType.newInstance();
        oArray[1] = componentType.newInstance();
        declaredField.set(o, oArray);
        if (needReflect(componentType)) {
            for (int i = 0; i < 2; i++) {
                setDefaultValue(componentType, oArray[i]);
            }
        }
    }

    /**根据class生成数组
     * @param c 对象class类型
     * @param <T> 数组类型
     * @return T[]
     */
    @SuppressWarnings("unchecked")
    private static <T> T[] getObjectArray(Class<?> c) {
        return ( T[] ) Array.newInstance(c, 2);

    }

    /**是否需要反射 自定义的javabean需要,其它不需要
     * @param c 对象class类型
     * @return boolean true 需要 ,false 不需要
     */
    private static boolean needReflect(Class c) {
        return !(c == BigInteger.class||c == BigDecimal.class || c == String.class
                || c.isPrimitive() || isBaseTypePackaging(c));
    }

    /**是否是基本类型的包装类
     * @param c 对象class类型
     * @return boolean true 是 ,false 否
     */
    private static boolean isBaseTypePackaging(Class c) {
        return c.equals(java.lang.Integer.class) || c.equals(java.lang.Byte.class) || c.equals(java.lang.Long.class) || c.equals(java.lang.Double.class) || c.equals(java.lang.Float.class) || c.equals(java.lang.Character.class) || c.equals(java.lang.Short.class) || c.equals(java.lang.Boolean.class);
    }



 }
